// Copyright (c) Symbian Ltd 2008. All rights reserved.

#include "rpsgameengine.h"
#include "common.hrh"

const TInt KPeriod = KOneSecondInMicroSeconds/30; 
const TTimeIntervalSeconds KInactivityTimeout = 30; // 30 seconds user inactivity timeout

class CInactivityTimer : public CTimer
	{
public:
	static CInactivityTimer* NewL(CRpsGameEngine& aGameEngine);
	void StartInactivityMonitor(TTimeIntervalSeconds aSeconds);
protected:
	CInactivityTimer(CRpsGameEngine& aRpsGameEngine);
	virtual void RunL();
private:
	CRpsGameEngine& iGameEngine;
	TTimeIntervalSeconds iTimeout;
	};
	
CInactivityTimer::CInactivityTimer(CRpsGameEngine& aRpsGameEngine)
: CTimer(EPriorityLow), iGameEngine(aRpsGameEngine)
	{
	CActiveScheduler::Add(this);
	}

CInactivityTimer* CInactivityTimer::NewL(CRpsGameEngine& aRpsGameEngine)
	{
	CInactivityTimer* me = new (ELeave) CInactivityTimer(aRpsGameEngine);
	CleanupStack::PushL(me);
	me->ConstructL();
	CleanupStack::Pop(me);
	return (me);
	}

void CInactivityTimer::StartInactivityMonitor(TTimeIntervalSeconds aSeconds)
	{
	if (!IsActive())
		{
		iTimeout = aSeconds;
		Inactivity(iTimeout);
		}
	}

void CInactivityTimer::RunL()
	{// Game has been inactive - no user input for iTimeout seconds
	iGameEngine.StopHeartbeat(ETrue); // Stops the game loop
	}


// ============================================================================
// CRpsGameEngine
// ============================================================================
CRpsGameEngine* CRpsGameEngine::NewL(MEngineObserver& aObs)
	{
	CRpsGameEngine* me = new (ELeave) CRpsGameEngine(aObs);
	CleanupStack::PushL(me);
	me->ConstructL();
	CleanupStack::Pop(me);
	return (me);
	}

/*
============================================================================
CRpsGameEngine's second phase constructor 
============================================================================
*/
void CRpsGameEngine::ConstructL()
	{
	// Game screen manager
	iGameScreenMgr = CGameScreenManager::NewL(*this);	
	// Create timer for game loop.
	iPeriodicTimer = CPeriodic::NewL(CActive::EPriorityStandard);
	// Create the inactivity timer
	iInactivity = CInactivityTimer::NewL(*this);
   	}

/*
============================================================================
CRpsGameEngine's constructor 
============================================================================
*/
CRpsGameEngine::CRpsGameEngine(MEngineObserver& aObs)
: 	iObs(aObs)
	{}

/*
============================================================================
CRpsGameEngine's destructor
============================================================================
*/
CRpsGameEngine::~CRpsGameEngine()
	{
	StopHeartbeat();
	delete iPeriodicTimer;
	
	if (iInactivity)
		{
		iInactivity->Cancel();
		delete iInactivity;
		}
	
	delete iGameScreenMgr;
	}

/*
============================================================================
Redraw the view every KPeriod and start monitoring the player inactivity.
============================================================================
*/
void CRpsGameEngine::StartHeartbeat()
	{
	if (!iPeriodicTimer->IsActive())
		iPeriodicTimer->Start(KPeriod, KPeriod, TCallBack(CRpsGameEngine::Tick, this));		
		
	iInactivity->StartInactivityMonitor(KInactivityTimeout); // Notify if inactive for KInactivityTimeout	
	}

/*
============================================================================
Called when the game loses focus, closes or inactivity timeout occurs
Called by the CRpsDestructor, so iPeriodicTimer pointer must be verified before use
============================================================================
*/
void CRpsGameEngine::StopHeartbeat(TBool aTimedOut /*=EFalse*/)
	{
	if (aTimedOut) 	// Only pause the game if a timeout 
		{	
		PauseGame(); // Pause the game
		}
	
	if (iPeriodicTimer)
		{
		if (iPeriodicTimer->IsActive())
			{
			iPeriodicTimer->Cancel();
			}
		}
	}

/*
============================================================================
Called by framework when application focus changes
============================================================================
*/
void CRpsGameEngine::FocusChanged(TBool aFocus)
	{
	if (aFocus)
		{// Focus gained
		StartHeartbeat();
		}
	else
		{// Focus lost
		StopHeartbeat();
		}
	}

/*
============================================================================
Handles key events
============================================================================
*/
void CRpsGameEngine::KeyEvent(TUint& aKeyState)
	{
	CGameScreen* gameScreen = iGameScreenMgr->GameScreen();
	ASSERT(gameScreen);
	gameScreen->ProcessInput(aKeyState);		
	}

/*
============================================================================
Kick off the drawing of the current screen
============================================================================
*/
void CRpsGameEngine::DrawGameScreen()
	{
	CGameScreen* gameScreen = iGameScreenMgr->GameScreen(); 
	ASSERT(gameScreen);
	gameScreen->DrawGameScreen();
	}
	
/*
============================================================================
Pause the game. The pause screen is displayed
============================================================================
*/
void CRpsGameEngine::PauseGame()
	{
	iGameScreenMgr->SetGameState(CGameScreenManager::EPausedScreen); // Switch on the pause screen
	iGameScreenMgr->GameData().iRpsError = KErrTimedOut;
	iObs.UpdateScreen();		
	}

/*
============================================================================
Restart the game after a pause
============================================================================
*/
void CRpsGameEngine::UnpauseGame()
	{// Start the game ticking again
	StartHeartbeat();
	}

// --------------------------------------------------------------------------
// Tick(TAny *aPtr)
// --------------------------------------------------------------------------
TInt CRpsGameEngine::Tick(TAny* aCallback)
	{
	ASSERT(aCallback);
	static_cast<CRpsGameEngine*>(aCallback)->GameLoop();

	// Returning a value of ETrue indicates the callback should be done again.
	return ETrue;
	}

// --------------------------------------------------------------------------
// GameLoop()
// --------------------------------------------------------------------------
void CRpsGameEngine::GameLoop()
	{
	iObs.UpdateScreen();
	}
